//============================================================================
// Author      : Ting Lei, leiting@gmail.com
// Version     :
// Copyright   : all rights reserved, see LICENSE file
// Description : For reading input data from database server
//============================================================================

#include <postgres.h>
#include <executor/spi.h>
#include <utils/builtins.h>

#include <string.h>

#include "input_t.h"

//copy a cstring into a cstring using regular SPI_palloc()
//note!: this function must be put in the same source .c file as where it is used; otherwise it causes crash
//SPI_palloc: This function can only be used while connected to SPI. Otherwise, it throws an error.
char *cp_cstring(const char *what)
{
//	elog(NOTICE, "cp_cstring(): input = '%s'", what);  //debug

    int len = strlen(what);
//	elog(NOTICE, "cp_cstring(): len = %d", len);  //debug

    char *dup = SPI_palloc(len+1);
    memcpy(dup, what, len);
    dup[len] = 0;
//	elog(NOTICE, "cp_cstring(): dup = '%s'", dup);  //debug

    return dup;
}

int readtable_mincost(char* command, input_t** p_edge_tuples)
{
		input_t* edge_tuples = NULL; //note: should dereference only after mem alloc

    	//char* command = "SELECT * FROM mini_net;";
    	int count;
    	bool isnull;
    	char* array_str1;
    	char* array_str2; 
    	int string_len;
    	int origin_fld, destination_fld, capacity_fld, lowerbound_fld, cost_fld, value_fld, vname_fld;

//        elog(NOTICE, "readtable_mincost(): ok0 edge_tuples = %d", edge_tuples);  //debug
//        elog(NOTICE, "readtable_mincost(): cmd = %s", command);  //debug

        int SPIcode = SPI_connect();

	    if (SPIcode  != SPI_OK_CONNECT) {
	        elog(ERROR, "Couldn't open a connection to SPI");
	        SPI_finish(); 
	        // return(55);
	    }

	    SPIcode = SPI_execute(command, true, 0);
//	    SPIcode = SPI_execute(command, false, 0); //!debug
       	if (SPIcode  != SPI_OK_SELECT) {
	        elog(ERROR, "Couldn't open a connection to SPI");
	        SPI_finish(); 
	        // return(233);
	    }

       	count = SPI_processed;
        if (count > 0) {
        	*p_edge_tuples = (input_t *) SPI_palloc(count * sizeof(input_t));
        	edge_tuples = *p_edge_tuples;
//        	edge_tuples = (input_t *) SPI_palloc(count * sizeof(input_t));
//            elog(NOTICE, "readtable_mincost(): ok0.5 edge_tuples = %d", edge_tuples);  //debug
        }


        TupleDesc tupdesc = SPI_tuptable->tupdesc;

//        elog(NOTICE, "readtable_mincost(): ok1");  //debug

        //get field id numbers
        origin_fld      = SPI_fnumber(tupdesc, "origin");
        destination_fld = SPI_fnumber(tupdesc, "destination");
        capacity_fld    = SPI_fnumber(tupdesc, "capacity");
        lowerbound_fld  = SPI_fnumber(tupdesc, "lowerbound");
        cost_fld        = SPI_fnumber(tupdesc, "cost");
        value_fld        = SPI_fnumber(tupdesc, "value");
        vname_fld     = SPI_fnumber(tupdesc, "vname");
        if (origin_fld <= 0 || destination_fld <= 0 || capacity_fld <= 0 || lowerbound_fld <= 0 || cost_fld <= 0 || value_fld <= 0 || vname_fld <= 0) {
        	elog(ERROR, "One of the following required fields is missing in the input table: origin, destination, capacity, lowerbound, cost, value, vname.");
        }

        //get field values
        for (int i = 0; i < count; i ++){
        	HeapTuple tuple = SPI_tuptable->vals[i];

        	//get string values : https://www.postgresql.org/docs/current/spi-interface-support.html
        	//https://grokbase.com/t/postgresql/pgsql-general/068efze9jq/text-datum-vardata-and-strings
//        	str = DatumGetCString(DirectFunctionCall1(textout, datumval));
        	edge_tuples[i].origin_c = cp_cstring(SPI_getvalue(tuple, tupdesc, origin_fld)); //1);       //pfree() in my_func.c //need to duplicate cstring b/c it can be freed during SPI_finish
        	edge_tuples[i].destination_c = cp_cstring(SPI_getvalue(tuple, tupdesc, destination_fld));  //pfree()
//        	edge_tuples[i].source_c = DatumGetInt64(SPI_getbinval(tuple, tupdesc, 1, &isnull));
//        	edge_tuples[i].destination_c = DatumGetInt64(SPI_getbinval(tuple, tupdesc, 2, &isnull));
			edge_tuples[i].capacity_c = DatumGetInt64(SPI_getbinval(tuple, tupdesc, capacity_fld, &isnull));
			edge_tuples[i].lowerbound_c = DatumGetInt64(SPI_getbinval(tuple, tupdesc, lowerbound_fld, &isnull));
			edge_tuples[i].cost_c = DatumGetFloat8(SPI_getbinval(tuple, tupdesc, cost_fld, &isnull));
			edge_tuples[i].value_c = DatumGetInt64(SPI_getbinval(tuple, tupdesc, value_fld, &isnull));
        	edge_tuples[i].vname_c = cp_cstring(SPI_getvalue(tuple, tupdesc, vname_fld));       //pfree() in my_func.c
//            elog(NOTICE, "readtable_mincost() read # %d, (%s, %s, %d,..)", i, edge_tuples[i].origin_c, edge_tuples[i].destination_c, edge_tuples[i].capacity_c);  //debug
        }
      
//        elog(NOTICE, "readtable_mincost() read %d records: ok done", count);  //debug
//        elog(NOTICE, "readtable_mincost() read (%s, %s, %d,..)...", edge_tuples[0].origin_c, edge_tuples[0].destination_c, edge_tuples[0].capacity_c);  //debug

        SPI_finish();  

        return (count);
}
       
	                   
